package com.crane.oss.sys.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crane.common.core.dto.SessParty;
import com.crane.common.core.dto.SessUser;
import com.crane.common.core.enums.ConstantEnums;
import com.crane.common.core.exception.AppException;
import com.crane.common.core.exception.BasicErrorCode;
import com.crane.common.core.exception.BizException;
import com.crane.common.framework.utils.BeanUtil;
import com.crane.oss.sys.bean.request.role.AddRoleRequest;
import com.crane.oss.sys.bean.request.role.QueryRoleRequest;
import com.crane.oss.sys.bean.request.role.UpdateRoleRequest;
import com.crane.oss.sys.bean.resp.MenuBean;
import com.crane.oss.sys.bean.resp.RoleBean;
import com.crane.oss.sys.bean.resp.UserBean;
import com.crane.oss.sys.dao.RoleDao;
import com.crane.oss.enums.RoleTypeEnum;
import com.crane.oss.enums.UserTypeEnum;
import com.crane.oss.sys.model.Role;
import com.crane.oss.sys.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

@Service("roleService")
public class RoleServiceImpl implements RoleService {

    private static final Logger logger = LoggerFactory.getLogger(RoleServiceImpl.class);

    @Resource
    protected RoleDao roleDao;

    @Resource
    protected UserRoleService userRoleService;

    @Resource
    protected MenuService menuService;

    @Resource
    protected RoleMenuService roleMenuService;

    @Resource
    protected PartyRoleService partyRoleService;

    @Override
    public RoleBean queryRole(Long id) {
        logger.info("RoleServiceImpl queryRole id={}", id);
        Role role = roleDao.selectById(id);
        if (null == role) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "角色");
        }
        RoleBean roleBean = new RoleBean();
        BeanUtil.copyProperties(role, roleBean);
        return roleBean;
    }

    @Override
    public IPage<RoleBean> queryList(QueryRoleRequest queryRequest) {
        logger.info("RoleServiceImpl queryList queryRequest={}", JSON.toJSON(queryRequest));
        IPage<Role> page = roleDao.selectPageRoleList(new Page<>(queryRequest.getPageNo(), queryRequest.getPageSize()),queryRequest);
        return page.convert(u -> {
            RoleBean v = new RoleBean();
            BeanUtils.copyProperties(u, v);
            return v;
        });
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(AddRoleRequest request, SessUser opUser) {
        logger.info("RoleServiceImpl save request={}", request);
        Role role = new Role();
        BeanUtil.copyProperties(request, role);
        role.setCreateUserId(opUser.getUserId());
        role.setCreateTime(new Date());
        checkRolePrems(role, request.getMenuIdList(), opUser);
        // 0 不可删除 1用户创建可删除
        if (opUser.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())) {
            role.setType(RoleTypeEnum.SYSTEM_ADMIN.getType());
        } else {
            role.setType(RoleTypeEnum.COMMON_USER.getType());
        }
        role.setStatus(ConstantEnums.STATUS.VALID.getValue());
        roleDao.insert(role);
        // 保存角色与菜单关系
        roleMenuService.saveBatch(role.getId(), opUser.getUserId(), request.getMenuIdList());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UpdateRoleRequest updateRequest, SessUser opUser) {
        logger.info("RoleServiceImpl update request={}", updateRequest);
        Role role = roleDao.selectById(updateRequest.getId());
        if (null == role) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "角色");
        }
        // 只能修改自己创建的角色
        if (opUser.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())
                && !role.getCreateUserId().equals(opUser.getUserId())) {
            logger.warn("someone tried to attack the server");
            throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
        }
        BeanUtil.copyProperties(updateRequest, role);

        checkRolePrems(role, updateRequest.getMenuIdList(), opUser);
        roleDao.updateById(role);
        // 修改角色与菜单关系
        roleMenuService.updateBatch(role.getId(), opUser.getUserId(), updateRequest.getMenuIdList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long roleId, SessUser opUser) {
        logger.info("RoleServiceImpl delete roleId={}", roleId);
        Role role = roleDao.selectById(roleId);
        if (null == role) {
            throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "角色");
        }
        if (role.getType().equals(0)) {
            throw new BizException("系统角色不能删除");
        }
        // 只能修改自己创建的角色
        if (opUser.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())
                && !role.getCreateUserId().equals(opUser.getUserId())) {
            logger.warn("someone tried to attack the server");
            throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
        }
        roleDao.deleteById(roleId);
        // 删除角色与菜单关系
        roleMenuService.deleteByRoleId(roleId);
        // 删除角色与用户关系
        userRoleService.deleteByRoleId(roleId);
        // 删除角色与机构关系
        partyRoleService.deleteByRoleId(roleId);
    }

    @Override
    public List<RoleBean> getUserRole(UserBean userBean) {
        logger.info("UserRoleServiceImpl getUserRole user={}", JSON.toJSON(userBean));
        if (!userBean.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())) {
            List<Role> userRoleLs = roleDao.getUserRole(userBean.getUserId());
            List<RoleBean> resultList = BeanUtil.copyList(userRoleLs, RoleBean.class);
            return resultList;
        }
        return new ArrayList<RoleBean>();
    }

    @Override
    public void validatorRole(List<Long> roleList, Long userId) {
        logger.info("UserRoleServiceImpl validatorRole roleList={}", roleList);
        List<Long> result = new ArrayList<>();
        List<Role> roleLs = roleDao.selectList(Wrappers.lambdaQuery(Role.class).eq(Role::getCreateUserId,userId));
        for (Role role : roleLs) {
            if (role.getStatus().equals(ConstantEnums.STATUS.VALID.getValue())) {
                result.add(role.getId());
            }
        }
        // 判断是否越权
        if (!result.containsAll(roleList)) {
            throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
        }
    }

    @Override
    public List<RoleBean> queryRoleListByCreateUser(SessUser opUser, SessParty party) {
        logger.info("UserRoleServiceImpl queryRoleListByCreateUser user={}", opUser.getUserName());
        Map<String, Object> map = new HashMap<>();
        map.put("createUserId", opUser.getUserId());
        map.put("status", ConstantEnums.STATUS.VALID.getValue());
        List<Role> roleLs = roleDao.selectList(Wrappers.lambdaQuery(Role.class).
                eq(Role ::getStatus,ConstantEnums.STATUS.VALID.getValue())
                .eq(Role ::getCreateUserId,opUser.getUserId()));
        List<RoleBean> resultList = BeanUtil.copyList(roleLs, RoleBean.class);
        return resultList;
    }

    @Override
    public RoleBean queryRoleAndMenuList(Long roleId, SessUser opUser) {
        logger.info("UserRoleServiceImpl queryRoleAndMenuList roleId={}", roleId);
        RoleBean roleBean = this.queryRole(roleId);
        List<Long> menuIdList = new ArrayList<>();
        roleBean.setMenuIdList(menuIdList);

        // List<MenuBean> menuBeanList=menuService.queryRoleMenuList(roleId);
        List<MenuBean> menuBeanList = menuService.queryRoleBtnMenuList(roleId);
        for (MenuBean menuBean : menuBeanList) {
            menuIdList.add(menuBean.getId());
        }
        return roleBean;
    }

    /**
     * 角色权限检查
     *
     * @param role
     * @param sysUser
     * @throws AppException
     */
    private void checkRolePrems(Role role, List<Long> menuIdList, SessUser sysUser) {
        // 不是超级管理员
        if (!sysUser.getUserType().equals(UserTypeEnum.SUPER_ADMIN.getType())) {
            if (role.getParentId() == null) {
                throw new AppException(BasicErrorCode.PARAS_IS_NOT_NULL, "parentId");
            }
            // 查询当前用户的角色id
            List<Role> rolels = roleDao.getUserRole(sysUser.getUserId());
            if (rolels.size() == 0) {
                throw new AppException(BasicErrorCode.ENTITY_NOT_EXISTS, "用户角色");
            }
            // 必须是当前创建用户所拥有的角色
            boolean flag = false;
            for (Role temp : rolels) {
                if (temp.getId().equals(role.getParentId())) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                logger.warn("someone tried to attack the server");
                throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
            }
            // 查询用户 某个角色下所拥有的菜单列表
            if (!CollectionUtils.isEmpty(menuIdList)) {
                List<MenuBean> menuBeanList = menuService.queryRoleMenuList(role.getParentId());
                // 判断是否越权
                for (Long menuId : menuIdList) {
                    for (MenuBean menuBean : menuBeanList) {
                        if (menuBean.getId().equals(menuId)) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        throw new AppException(BasicErrorCode.NO_DATA_RIGHT);
                    }
                }
            }
        }
    }

}
